﻿using System;
using System.Collections.Generic;
using System.Globalization;

namespace Gmantis.Controls
{
    public enum MaskFormat
    {
        IncludePrompt,
        IncludeLiterals,
        IncludePromptAndLiterals,
        ExcludePromptAndLiterals
    }

    internal abstract class MaskToken
    {
        // Fields
        private int _editCounter;
        private readonly string _originalSymbol;
        private readonly TokenizedMask _ownerMask;

        // Methods
        public MaskToken(TokenizedMask ownerMask, string symbol)
        {
            this._ownerMask = ownerMask;
            this._originalSymbol = symbol;
        }

        internal void BeginEdit()
        {
            if (this._editCounter == 0)
            {
                this._editCounter++;
                this.BeginEditInternal();
            }
        }

        protected virtual void BeginEditInternal()
        {
        }

        internal void CancelEdit()
        {
            if (this._editCounter > 0)
            {
                this._editCounter = 0;
                this.CancelEditInternal();
            }
        }

        protected virtual void CancelEditInternal()
        {
        }

        internal void EndEdit()
        {
            if (this._editCounter > 0)
            {
                this._editCounter--;
                if (this._editCounter == 0)
                {
                    this.EndEditInternal();
                }
            }
        }

        protected virtual void EndEditInternal()
        {
        }

        public abstract bool MatchSymbol(string symbol);

        // Properties
        protected CultureInfo Culture
        {
            get
            {
                return this.OwnerMask.Culture;
            }
        }

        internal bool IsEdit
        {
            get
            {
                return (this._editCounter > 0);
            }
        }

        public abstract bool IsLiteral { get; }

        public string OriginalSymbol
        {
            get
            {
                return this._originalSymbol;
            }
        }

        public abstract string OutputSymbol { get; }

        public TokenizedMask OwnerMask
        {
            get
            {
                return this._ownerMask;
            }
        }
    }

    internal class LiteralToken : MaskToken
    {
        // Methods
        public LiteralToken(TokenizedMask ownerMask, string symbol)
            : base(ownerMask, symbol)
        {
        }

        public override bool MatchSymbol(string symbol)
        {
            return (symbol == this.OutputSymbol);
        }

        // Properties
        public override bool IsLiteral
        {
            get
            {
                return true;
            }
        }

        public override string OutputSymbol
        {
            get
            {
                return base.OriginalSymbol;
            }
        }
    }

    internal class PromptToken : MaskToken
    {
        // Fields
        private bool? _isUppercase;
        private readonly Func<string, bool> _matchDelegate;
        private string _proposedValue;
        private string _value;

        // Methods
        public PromptToken(TokenizedMask ownerMask, string symbol, bool? isUppercase)
            : base(ownerMask, symbol)
        {
            this._isUppercase = isUppercase;
            this._matchDelegate = ownerMask.GetMatchPromptDelegate(symbol);
        }

        protected override void BeginEditInternal()
        {
            base.BeginEditInternal();
            this._proposedValue = this._value;
        }

        protected override void CancelEditInternal()
        {
            base.CancelEditInternal();
            this._proposedValue = null;
        }

        public void ClearValue()
        {
            this.Value = null;
        }

        protected override void EndEditInternal()
        {
            base.EndEditInternal();
            this._value = this._proposedValue;
        }

        public override bool MatchSymbol(string symbol)
        {
            if (!base.OwnerMask.IsResetSymbol(symbol))
            {
                return this.MatchDelegate(symbol);
            }
            return true;
        }

        // Properties
        public bool IsEmpty
        {
            get
            {
                return string.IsNullOrEmpty(base.IsEdit ? this._proposedValue : this._value);
            }
        }

        public override bool IsLiteral
        {
            get
            {
                return false;
            }
        }

        public bool? IsUppercase
        {
            get
            {
                return this._isUppercase;
            }
        }

        protected Func<string, bool> MatchDelegate
        {
            get
            {
                return this._matchDelegate;
            }
        }

        public override string OutputSymbol
        {
            get
            {
                return this.Value;
            }
        }

        protected string ProposedValue
        {
            get
            {
                return this._proposedValue;
            }
        }

        public string Value
        {
            get
            {
                string str = base.IsEdit ? this._proposedValue : this._value;
                if (!string.IsNullOrEmpty(str))
                {
                    return str;
                }
                return base.OwnerMask.PromptPresenter;
            }
            set
            {
                string str = base.OwnerMask.IsResetSymbol(value) ? null : value;
                bool? isUppercase = this.IsUppercase;
                if ((str != null) && isUppercase.HasValue)
                {
                    str = isUppercase.Value ? str.ToUpper(base.Culture) : str.ToLower(base.Culture);
                }
                if (base.IsEdit)
                {
                    this._proposedValue = str;
                }
                else
                {
                    this._value = str;
                }
            }
        }
    }

    internal class MaskTokenCollection : List<MaskToken>
    {
    }
}
